package com.acerola.thread;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @program: Chatting
 * @description:阻塞线程池
 * @author: Acerola
 * @create: 2022-12-03 21:22
 **/
@Slf4j
public class CustThreadPoolExecutor {
    private ThreadPoolExecutor pool = null;
    private int CORE_POOL_SIZE = 1;
    private int MAXIMUM_POOL_SIZE = 3;
    private int KEEP_ALIVE_TIME = 30;

    public CustThreadPoolExecutor() {
        this.pool = null;
        this.CORE_POOL_SIZE = 1;
        this.MAXIMUM_POOL_SIZE = 3;
        this.KEEP_ALIVE_TIME = 30;
    }
    public CustThreadPoolExecutor(int CORE_POOL_SIZE, int MAXIMUM_POOL_SIZE, int KEEP_ALIVE_TIME) {
        this.pool = null;
        this.CORE_POOL_SIZE = CORE_POOL_SIZE;
        this.MAXIMUM_POOL_SIZE = MAXIMUM_POOL_SIZE;
        this.KEEP_ALIVE_TIME = KEEP_ALIVE_TIME;
    }

    /**
     * 线程池初始化方法
     */
    public void init() {
        pool = new ThreadPoolExecutor(
                CORE_POOL_SIZE,
                MAXIMUM_POOL_SIZE,
                KEEP_ALIVE_TIME,
                TimeUnit.MINUTES,
                new ArrayBlockingQueue<>(10),
                new CustThreadFactory(),
                new CustRejectedExecutionHandler());
    }

    public void destroy() {
        if (pool != null) {
            pool.shutdown();
        }
    }

    public ExecutorService getCustThreadPoolExecutor() {
        return this.pool;
    }

    private class CustThreadFactory implements ThreadFactory {
        private AtomicInteger count = new AtomicInteger(0);

        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r);
            String threadName = CustThreadPoolExecutor.class.getSimpleName() + count.addAndGet(1);
            System.out.println(threadName);
            t.setName(threadName);
            return t;
        }
    }

    private class CustRejectedExecutionHandler implements RejectedExecutionHandler {

        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            try {
                // 核心改造点，由blockingQueue的offer改阻塞成put阻塞方法
                // 如果BlockQueue没有空间,则调用此方法的线程被阻断直到BlockingQueue里面有空间再继续
                // 这样所提交的任务全部有机会执行
                executor.getQueue().put(r);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
